package cn.fhj.sohu;

import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.swing.JOptionPane;
import javax.swing.JProgressBar;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import cn.fhj.util.IoUtil;
import cn.fhj.util.MsgException;
import cn.fhj.util.StringUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class Backup {
	private static final String T2_PIC_LIST_DO_I = "/t2/picList.do?i=";
	private static final String ROOT = "http://w.sohu.com/t2/";
	private String saveDir = "c:/sohu/fzz/";
	private String boker = ROOT + "othdoc.do?v_u=";
	private static final String USER_HOME = ROOT + "othdoc.do?v_u=";
	private static final String MBLOG = "http://s1.t.itc.cn/mblog/pic/";
	private static final int LINK_BLOCK = 100;
	private static final String LIB = "lib/";
	private static final String MORE = "http://t.sohu.com/twAction/msgMore?msgid=";
	protected DefaultHttpClient client;

	private static final String SINGLE = "http://t.sohu.com/m/";
	private final static Log log = LogFactory.getLog(Backup.class);

	private final String name;

	private boolean includedPic;

	public Backup(String saveDir, String bokName, JProgressBar progress, boolean includedPic) {
		this.saveDir = saveDir;
		this.name = bokName;
		this.progress = progress;
		this.includedPic = includedPic;
	}

	public Backup() {
		name = "";
		client = new DefaultHttpClient();
	}

	public String getBokId(String name) {
		if (client == null) {
			client = new DefaultHttpClient();// 得到httpclient实例
		}
		Element body;
		try {
			body = getBody("http://t.sohu.com/n/" + name);
		} catch (IllegalArgumentException e) {
			return null;
		}
		Elements mainTs = body.getElementsByClass("mainT");
		if (mainTs.isEmpty()) {
			return null;
		}
		String follows = "t-follows";
		for (Element e : mainTs.get(0).getElementsByAttribute(follows)) {
			// <a class="btn btn2 js-send-follows js-show-register"
			// t-follows="9651952"
			// onclick="kola('newt.util.Tool', function (Tool) {Tool.iNoLogin();});"><b><i
			// class="add"><q class="k1"></q><q class="k2"></q></i>关注</b></a>
			return e.attr(follows);
		}
		return null;
	}

	protected void createLibs() {
		for (String s : new String[] { "jquery-2.1.1.min.js", "style.css" }) {
			IoUtil.write(Backup.class.getResourceAsStream('/' + s), saveDir + "lib/" + s);
		}
	}

	private void writeActionJs(int totalPage, int totalComment, String searchKey) throws Exception {
		String fileName = "action.js";
		Configuration config = new Configuration();
		config.setEncoding(Locale.getDefault(), "UTF-8");
		config.setClassForTemplateLoading(Backup.class, "/ftl");
		Template template = config.getTemplate(fileName);
		Map map = new HashMap();
		map.put("bockerName", name);
		map.put("totalPage", totalPage);
		map.put("totalComment", totalComment);
		map.put("searchKey", searchKey);
		template.setEncoding("UTF-8");
		StringWriter writer = new StringWriter();
		template.process(map, writer);
		IoUtil.write(writer.toString().getBytes("UTF-8"), saveDir + "lib/" + (searchKey != null ? "search" : "")
				+ fileName);
		createLibs();
		if (searchKey != null) {
			openFirstPage(searchKey != null);
		}
	}

	private String getHtmlName(int i, boolean searched) {
		return saveDir + (searched ? "search/" : "") + String.valueOf(10000 + i).substring(1) + ".html";
	}

	private List<Comment> readPage(int i) {
		List<Comment> result = new ArrayList();
		Elements t4List = Jsoup.parseBodyFragment(read(boker + "&cp=" + i)).body().getElementsByClass("section")
				.first().children();
		for (Element t4 : t4List) {
			Comment comment = new Comment();
			comment.setId(Long.parseLong(getCommentId(t4)));
			Element t4a = t4.getElementsByClass("t4a").first();
			comment.setTime(t4a.child(0).text());
			if (comment.isVagueTime()) {
				getDetailTime(comment);
			}
			Element root = getRoot(t4);
			if (root != null) {
				comment.setRt(getRootComment(root));
				root.remove();
			}
			setPic(t4, comment);
			result.add(comment);
		}
		return result;
	}

	private String getCommentId(Element t4) {
		return t4.getElementsByTag("a").get(0).attr("name").substring(1);
	}

	private Element getBody(String url) {
		return Jsoup.parseBodyFragment(read(url)).body();
	}

	private Comment getRootComment(Element root) {
		Comment comment = new Comment();
		comment.setId(getRootId(root));
		String author = root.getElementsByTag("a").get(0).text();
		if (!author.equals('@' + name)) {
			comment.setAuthor(author.substring(1));
		}
		setPic(root, comment);
		return comment;
	}

	private long getRootId(Element root) {
		// <a
		// href="/t2/comment.do?i=11402803774&amp;from_type=&amp;b_u=L3QyL290aGRvYy5kbz92X3U9OTY1MTk1MiN0MTE0MDM1MTAyMTY#cmt">评论原文(36)</a>
		Elements aa = root.getElementsByTag("a");
		String href = aa.last().attr("href");
		String idStr = href.substring(href.indexOf("?i=") + 3, href.indexOf("&"));
		return Long.parseLong(idStr);
	}

	private void setPic(Element t4, Comment comment) {
		for (Element e : t4.getElementsByTag("a")) {
			String href = e.attr("href");
			if (isSinlePic(href) && e.text().contains("原图")) {
				comment.setPic(href);
				break;
			} else if (href.startsWith(T2_PIC_LIST_DO_I) && e.text().contains("组图")) {
				comment.setMultiPic(true);
				break;
			}

		}
	}

	public void setProgress(String msg) {
		String s;
		if (progress.getValue() == 0) {
			s = null;
		} else if (progress.getValue() == progress.getMaximum()) {
			s = "100";
		} else {
			s = String.valueOf(progress.getValue() * (float) 100 / progress.getMaximum());
			if (s.length() > 4) {
				s = s.substring(0, 4);
			}
		}
		long t = (System.currentTimeMillis() - beginTime) / 1000;
		long hours = t / 3600;
		progress.setString("已耗时：" + (hours == 0 ? "" : hours + "时") + t / 60 % 60 + "分" + t % 60 + "秒， "
				+ (s == null ? "" : s + "% ") + msg);
	}

	private boolean isSinlePic(String href) {
		return href.length() > MBLOG.length()
				&& href.substring(0, MBLOG.length()).matches("http://s\\d{1}.t.itc.cn/mblog/pic/");
	}

	private Element getRoot(Element t4) {
		for (Element e : t4.children()) {
			if (e.classNames().contains("root")) {
				return e;
			}
		}
		return null;
	}

	private String getFileName(String picUrl) {
		String filename = saveDir + "pic/" + picUrl.charAt(8) + "/"
				+ picUrl.substring(MBLOG.length(), picUrl.lastIndexOf('/'));
		File file = new File(filename);
		file.mkdirs();
		return filename + picUrl.substring(picUrl.lastIndexOf('/'));
	}

	private int countComments(Element body) {
		for (Element e : body.children()) {
			if (e.tagName().equalsIgnoreCase("div") && e.attr("class").equals("t11")) {
				return Integer.parseInt(e.getElementsByClass("t6").get(1).getElementsByTag("span").get(0).text()
						.replaceAll("\\D", ""));
			}
		}
		return 0;
	}

	public String read(String url) {
		try {
			HttpGet httpGet = new HttpGet(url);
			HttpResponse response = client.execute(httpGet);

			HttpEntity entity = response.getEntity();
			String sb = read(entity);

			// 释放资源
			httpGet.abort();
			return sb;
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e) {
			throw new MsgException("Error while reading: " + url, e);
		}
	}

	private String read(HttpEntity entity) throws IOException, UnsupportedEncodingException {
		StringBuilder sb = new StringBuilder();
		// 输出页面内容
		if (entity != null) {
			String charset = ContentType.getOrDefault(entity).getCharset().name();
			InputStream is = entity.getContent();
			BufferedReader br = new BufferedReader(new InputStreamReader(is, charset));
			String line = null;
			while ((line = br.readLine()) != null) {
				sb.append(line + "\t\n");
			}
			is.close();
		}
		return sb.toString();
	}

	private JProgressBar progress;

	private void createAll() throws Exception {
		Set<Comment> comments = currentComments();
		deleteOldPages();
		createPages(comments);
		// download comments
		String ignorePicInc = saveDir + "lib/ignoredPicUrls.inc";
		if (includedPic) {
			File file = new File(ignorePicInc);
			if (file.exists()) {
				String[] urls = IoUtil.readList(ignorePicInc);
				progress.setValue(1);
				progress.setMaximum(urls.length);
				setProgress("下载之前被忽略的图片...");
				for (String url : urls) {
					savePic(url);
					progress.setValue(progress.getValue() + 1);
				}
				file.delete();
			}
		}
		setProgress("下载评论...");

		progress.setValue(0);
		progress.setMaximum(comments.size());
		ignoredPicUrls = new HashSet();
		existStatus = 1;
		for (Comment cm : comments) {
			try {
				this.saveComment(cm);
				if (cm.getRt() != null) {
					this.saveComment(cm.getRt());
				}
				progress.setValue(progress.getValue() + 1);
			} catch (Exception e) {
				log.error(e, e);
			}
			if (existStatus == 2) {
				existStatus = 0;
				break;
			}
		}
		existStatus = 0;
		String msg;
		if (progress.getValue() < progress.getMaximum()) {
			msg = "下载评论失败";
		} else {
			msg = "下载评论成功";
		}
		setProgress(msg);
		Collections.addAll(ignoredPicUrls, IoUtil.readList(ignorePicInc));
		IoUtil.save(ignoredPicUrls, ignorePicInc);
	}

	private void deleteOldPages() {
		for (File file : new File(saveDir).listFiles()) {
			if (file.isFile()) {
				file.delete();
			}
		}

	}

	private void createPages(Set<Comment> comments) throws Exception {

		int size = 20;
		int index = 0;
		int pageIndex = 0;
		List<Comment> page = new ArrayList();
		for (Comment cm : comments) {
			index++;
			page.add(cm);
			if (index % size == 0) {
				pageIndex++;
				createPage(page, pageIndex, false);
				page.clear();
			}
		}
		if (!page.isEmpty()) {
			createPage(page, pageIndex + 1, false);
		}
		writeActionJs((comments.size() + size - 1) / size, comments.size(), null);
	}

	private void openFirstPage(boolean searched) {
		try {
			Desktop desktop = Desktop.getDesktop();
			if (Desktop.isDesktopSupported() && desktop.isSupported(Desktop.Action.BROWSE)) {
				URI uri = new URI(saveDir + (searched ? "search/" : "") + "0001.html");
				desktop.browse(uri);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (URISyntaxException ex) {
			ex.printStackTrace();
		}
	}

	private void createPage(List<Comment> comments, int index, boolean searched) throws Exception {
		Configuration config = new Configuration();
		config.setEncoding(Locale.getDefault(), "UTF-8");
		config.setClassForTemplateLoading(Backup.class, "/ftl");
		Template template = config.getTemplate("page2.html");
		Map map = new HashMap();
		map.put("comments", comments);
		map.put("index", index);
		map.put("searched", searched);
		template.setEncoding("UTF-8");
		StringWriter writer = new StringWriter();
		template.process(map, writer);
		IoUtil.write(writer.toString().getBytes("UTF-8"), getHtmlName(index, searched));
	}

	private void saveComment(Comment comment) throws ClientProtocolException, IOException, TemplateException {
		File file = new File(saveDir + comment.getJsFile());
		if (file.exists()) {
			return;
		}
		Map<String, Object> map = new HashMap();
		new File(saveDir + comment.getDir()).mkdirs();
		String content = read(MORE + comment.getId());
		String succFlag = "\"status\":0";
		if (!content.contains(succFlag)) {
			throw new MsgException("Failed to retrieve comment:" + comment.getId());
		}
		map.put("content", content);

		if (comment.isMultiPic()) {
			savePics(comment);
		} else if (comment.getPic() != null) {
			addPic(comment, comment.getPic());
		}

		map.put("pics", comment.getPics());
		map.put("id", comment.getId());

		Configuration config = new Configuration();
		config.setEncoding(Locale.getDefault(), "UTF-8");
		config.setClassForTemplateLoading(Backup.class, "/ftl");
		Template template = config.getTemplate("comment.js");
		template.setEncoding("UTF-8");
		StringWriter writer = new StringWriter();
		template.process(map, writer);
		IoUtil.write(writer.toString().getBytes("UTF-8"), saveDir + comment.getJsFile());

	}

	private void savePics(Comment comment) throws ClientProtocolException, IOException {
		// <a
		// href="/t2/picList.do?i=11393518573&amp;suv=120538322096903&amp;b_u=L3QyL290aGRvYy5kbz92X3U9OTY1MTk1Mg">组图(3)</a>
		// http://t.sohu.com/preExpr/m/11393518573
		Elements smedias = Jsoup.parseBodyFragment(read("http://t.sohu.com/preExpr/m/" + comment.getId())).body()
				.getElementsByClass("smedia");
		for (Element e : smedias) {
			Elements srcPics = e.getElementsByAttributeValue("title", "查看原图");
			if (srcPics.size() == 1) {
				addPic(comment, srcPics.get(0).attr("href"));
			}
		}
	}

	private void addPic(Comment comment, String pic) throws ClientProtocolException, IOException {
		String picName = savePic(pic);
		comment.addPic(picName.substring(saveDir.length()));
	}

	private String savePic(String url) throws ClientProtocolException, IOException {
		String picName = getFileName(url);
		if (new File(picName).exists()) {
			return picName;
		}
		if (!includedPic) {
			recordIgnoredPic(url);
			return picName;
		}
		setProgress("下载: " + url.substring(7));
		HttpGet httpGet = new HttpGet(url);
		HttpResponse response = client.execute(httpGet);

		HttpEntity entity = response.getEntity();
		IoUtil.write(entity.getContent(), picName);
		httpGet.abort();
		setProgress("");
		return picName;
	}

	Set<String> ignoredPicUrls = new HashSet();

	private void recordIgnoredPic(String url) {
		ignoredPicUrls.add(url);
	}

	private String getIdListFilename() {
		return saveDir + "lib/idList.inc";
	}

	private void saveIds(Set<Comment> comments, int i) {
		if (comments.isEmpty()) {
			return;
		}
		new File(saveDir + LIB).mkdirs();
		StringBuilder sb = new StringBuilder();
		for (Comment cm : comments) {
			char insp = '\\';
			sb.append(cm.getId()).append(insp).append(cm.getTime()).append(insp).append(cm.getPicStatu());
			if (cm.getRt() != null) {
				sb.append(insp).append(cm.getRt().getId()).append(insp).append(cm.getRt().getPicStatu());
				String author = cm.getRt().getAuthor();
				if (author != null) {
					sb.append(insp).append(author);
				}
			}
			sb.append('\n');
		}
		sb.append(i).append('\\').append(countComments);
		try {
			IoUtil.write(sb.toString().getBytes("utf-8"), getIdListFilename());
		} catch (UnsupportedEncodingException e) {
			throw new MsgException(e);
		}
	}

	private int countComments = 0;

	private long beginTime;
	private int existStatus = 0;

	private Set<Comment> currentComments() {
		File file = new File(getIdListFilename());// file.length() 500000
		Set<Comment> oldComments = new LinkedHashSet();
		Set<Comment> newComments = new LinkedHashSet();
		long maxId = 0;
		int lastBackupPage = 0;
		setProgress("读取微博索引 ...");
		String page = read(boker);
		Document doc = Jsoup.parseBodyFragment(page);
		Element body = doc.body();
		countComments = countComments(body);
		int totalPage = (countComments + 9) / 10;
		int toRead = totalPage - oldComments.size() / 10;
		if (file.exists() && file.length() > 0) {
			setProgress("读取本地微博索引 ...");
			for (String ss : IoUtil.readText(file).split("\n")) {
				String[] s = ss.split("\\\\");
				if (s.length == 2) {
					lastBackupPage = Integer.parseInt(s[0]);
					if (lastBackupPage > 0) {
						int added = countComments - Integer.parseInt(s[1]);
						lastBackupPage += (added - 9) % 10;
					}
					break;
				}
				Comment comment = new Comment();
				comment.setId(Long.valueOf(s[0]));
				if (maxId < comment.getId()) {
					maxId = comment.getId();
				}
				comment.setTime(s[1]);
				if (comment.isVagueTime()) {
					getDetailTime(comment);
				}
				comment.setPicStatu(s[2]);
				if (s.length > 3) {
					Comment rt = new Comment();
					comment.setRt(rt);
					rt.setId(Long.parseLong(s[3]));
					rt.setPicStatu(s[4]);
					if (s.length > 5) {
						s[5] = s[5].replace("@", "");
						if (!s[5].equals(name)) {
							rt.setAuthor(s[5]);
						}
					}
				}
				oldComments.add(comment);
			}
		}
		existStatus = 1;
		boolean first = oldComments.isEmpty();
		int readingPage = 0;
		try {
			if (lastBackupPage > 0) {
				for (int i = lastBackupPage - 1;; i++) {
					int k = i - lastBackupPage + 1;
					if (k > toRead) {
						k = toRead;
					}
					setProgress("备份索引 " + k + " / " + toRead + "页 ...");
					List<Comment> list = this.readPage(i);
					if (list.isEmpty() && i > totalPage + 1) {
						break;
					}
					oldComments.addAll(list);
					readingPage = i + 1;
					if (existStatus == 2) {
						saveIds(oldComments, readingPage);
						existStatus = 0;
					}
				}
			}

			for (int i = 1;; i++) {
				int k = i + (lastBackupPage == 0 ? 0 : (totalPage - lastBackupPage));
				if (k > toRead) {
					toRead = k;
				}
				setProgress("备份索引 " + k + " / " + toRead + "页 ...");
				List<Comment> list = this.readPage(i);
				if (list.isEmpty() && i > totalPage + 1) {
					break;
				}
				newComments.addAll(list);
				readingPage = i + 1;
				if (existStatus == 2) {
					if (first) {
						saveIds(newComments, readingPage);
					}
					existStatus = 0;
				}
				if (!list.isEmpty() && list.get(list.size() - 1).getId() < maxId) {
					break;
				}
			}
			readingPage = totalPage;
		} catch (Exception e) {
			if (newComments.isEmpty() || oldComments.isEmpty()) {
				saveIds(first ? newComments : oldComments, readingPage);
				existStatus = 0;
			}
			throw e;
		}
		newComments.addAll(oldComments);
		saveIds(newComments, 0);
		existStatus = 0;
		return newComments;
	}

	private void excuteSearch(String searchkey) throws Exception {
		Set<Comment> comments = searchComments(searchkey.split("\\s+"));
		if (comments.isEmpty()) {
			return;
		}
		createSearchPages(comments, searchkey);
	}

	private void createSearchPages(Set<Comment> comments, String searchkey) throws Exception {
		File serachDir = new File(saveDir + "search/");
		if (serachDir.exists()) {
			for (File file : serachDir.listFiles()) {
				if (file.isFile()) {
					file.delete();
				}
			}
		} else {
			serachDir.mkdirs();
		}

		int size = 20;
		int index = 0;
		int pageIndex = 0;
		List<Comment> page = new ArrayList();
		for (Comment cm : comments) {
			index++;
			page.add(cm);
			if (index % size == 0) {
				pageIndex++;
				createPage(page, pageIndex, true);
				page.clear();
			}
		}
		if (!page.isEmpty()) {
			createPage(page, pageIndex + 1, true);
		}
		writeActionJs((comments.size() + size - 1) / size, comments.size(), searchkey);
	}

	private Set<Comment> searchComments(String... keys) {
		File file = new File(getIdListFilename());// file.length() 500000
		Set<Comment> oldComments = new LinkedHashSet();
		if (file.exists() && file.length() > 0) {
			int count = 1;
			for (String ss : IoUtil.readText(file).split("\n")) {
				String[] s = ss.split("\\\\");
				if (s.length == 2) {
					break;
				}
				int block = 600;
				setProgress("检索第 " + (count / block * block + 1) + " 到 " + (count / block * block + block) + " 条微博...");
				count++;
				Comment comment = new Comment();
				comment.setId(Long.valueOf(s[0]));
				comment.setTime(s[1]);
				if (comment.isVagueTime()) {
					getDetailTime(comment);
				}
				comment.setPicStatu(s[2]);
				if (s.length > 3) {
					Comment rt = new Comment();
					comment.setRt(rt);
					rt.setId(Long.parseLong(s[3]));
					rt.setPicStatu(s[4]);
					if (s.length > 5) {
						s[5] = s[5].replace("@", "");
						if (!s[5].equals(name)) {
							rt.setAuthor(s[5]);
						}
					}
				}
				if (contains(comment, keys)) {
					oldComments.add(comment);
				}
			}
		}
		setProgress("共搜到微博条数：" + oldComments.size());
		return oldComments;
	}

	private boolean contains(Comment comment, String[] keys) {
		String content = readComment(comment);
		for (String key : keys) {
			if (!content.contains(key)) {
				return false;
			}
		}
		return true;
	}

	private String readComment(Comment comment) {
		String s = getData(IoUtil.readText(new File(saveDir + comment.getJsFile())));
		if (comment.getRt() != null) {
			return s + ' ' + getData(IoUtil.readText(new File(saveDir + comment.getRt().getJsFile())));
		}
		return s;
	}

	public String getData(String s) {
		String beigin = "data\":\"";
		return s.substring(s.indexOf(beigin) + beigin.length(), s.indexOf("\",\"statusText"));
	}

	private void getDetailTime(Comment comment) {
		Elements twiB = Jsoup.parseBodyFragment(read(SINGLE + comment.getId())).body().getElementsByClass("twiB");
		Element time = twiB.first().text().contains("转发原文") ? twiB.get(1) : twiB.first();
		comment.setTime(time.getElementsByClass("tm").first().attr("title").substring(5));
	}

	public boolean canExit() {
		if (existStatus == 0) {
			return true;
		}
		if (existStatus == 1) {
			existStatus = 2;
		}
		return false;
	}

	
	private static final String TRY = "可以点“备份”按钮重试";

	private Map<String, String> linkMap;
	private Map<String, String> historyLinkMap;

	public String getRealUrl(String link) {
		initLinkMaps();
		// http://www.4icu.org/ph/
		// http://www.xys.org
		// http://goo.gl/5DDWmo
		// http://url.cn/Va5T6W

		String lowerCase = link.toLowerCase();
		boolean outLink = true;
		for (String ig : new String[] { "http://t.itc.cn/", "http://t.cn/", "http://url.cn/" }) {
			if (lowerCase.startsWith(ig)) {
				outLink = false;
				break;
			}
		}
		if (outLink) {
			return link;
		}

		String realUrl = linkMap.get(link);
		if (realUrl != null) {
			return realUrl;
		}
		realUrl = historyLinkMap.get(link);
		if (realUrl != null) {
			return realUrl;
		}
		try {
			URL url = new URL(link);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			try {
				conn.getResponseCode();
			} catch (Exception e) {
				if (conn.getURL().toString().equals(link)) {
					throw e;
				}
				// IGNORE
			}
			realUrl = conn.getURL().toString();
			conn.disconnect();
			linkMap.put(link, realUrl);
			return realUrl;
		} catch (Exception e) {
			throw new MsgException("Error in the link： " + link, e);
		}
	}

	private void initLinkMaps() {
		if (linkMap == null) {
			linkMap = readMap(curPage);
			if (historyLinkMap == null) {
				historyLinkMap = readMap(curPage - LINK_BLOCK);
			}
		}
	}

	private Map<String, String> readMap(int page) {
		Map<String, String> map = new HashMap();
		if (page < 0) {
			return map;
		}
		File file = new File(getLinkName(page));// file.length() 500000
		if (file.exists()) {
			if (file.length() > 500000) {
				file.delete();
				return map;
			}
			String content = IoUtil.readText(file);
			for (String s : content.split("\n")) {
				if (StringUtil.isEmpty(s)) {
					continue;
				}
				String[] ss = s.split("\r");
				map.put(ss[0], ss[1]);
			}
		}
		return map;
	}

	private String getLinkName(int page) {
		return saveDir + "lk" + page / LINK_BLOCK + ".inc";
	}

	private int curPage;

	public void excute() {
		new Thread() {
			public void run() {
				try {
					beginTime = System.currentTimeMillis();
					setProgress("查找微博用户：" + name + " ...");
					String id = Backup.this.getBokId(name);
					if (id == null) {
						JOptionPane.showMessageDialog(MainFrm.frm, "找不到微博用户： " + name + ", 请重新输入", "微博名称有误",
								JOptionPane.ERROR_MESSAGE);
						return;
					}
					boker = USER_HOME + id;
					new File(saveDir).mkdirs();
					createAll();

				} catch (Exception e) {
					log.error(e.getMessage(), e);
					setProgress("备份失败：" + e.getMessage() + ", " + TRY);
				} finally {
					MainFrm.finsihed();
				}
			}
		}.start();
	}

	public void search(final String keys) {
		new Thread() {
			public void run() {
				try {
					beginTime = System.currentTimeMillis();
					excuteSearch(keys);
				} catch (Exception e) {
					log.error(e.getMessage(), e);
					setProgress("搜索失败：" + e.getMessage() + ", " + TRY);
				} finally {
					MainFrm.finsihed();
				}
			}

		}.start();
	}
}